<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="test"></div>

        <!-- 这里全部更改为17.0.1版本的react -->
        <script crossorigin src="https://unpkg.com/react@17.0.1/umd/react.development.js"></script>
        <script crossorigin src="https://unpkg.com/react-dom@17.0.1/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
        
        <script type="text/babel">
            /* 
                1.初始化阶段:由ReactDOM.render()触发---初次渲染
                    1.constructor()
                    2.getDerivedStateFromProps()
                    3.render()
                    4.componentDidMount()   // 组件挂载完毕的钩子
                2.更新阶段:由组件内部this.setState()或父组件重新render触发
                    1.getDerivedStateFromProps()
                    2.shouldComponentUpdate()
                    3.render()
                    4.getSnapshotBeforeUpdate()
                    5.componentDidUpdate()
                3.卸载组件:由ReactDOM.unmountComponentANode()触发
                    1.componentWillUnmount()
            
            */
            // 创建组件
            class Count extends React.Component{
                // 构造器
                constructor(props){
                    console.log('Count---constructor');
                    super(props);
                    // 初始化状态
                    this.state={num:1}
                }
                // 从props那里得到一个派生的状态
                // 若state的值在任何时候都取决于props,那么就使用getDerivedStateFromProps
                // getDerivedStateFromProps没有太大意义
                static getDerivedStateFromProps(props,state){
                    // 这里返回 状态对象state Obj  或者 null   不能返回undefined
                    // 此方法适用于(罕见的用例)，即 state 的值在任何时候都取决于 props。
                    // 派生状态会导致代码冗余，并使组件难以维护
                    // 用处:例如:进行判断 传递过来的props某一个属性某一个值是多少,state初始化里面某一个属性某一个值是多少,做一个对比,奇数以谁为主,偶数以谁为主
                    console.log('getDerivedStateFromProps',props,state);
                    // return props

                    // 为了不影响后面操作返回null
                    return null
                }

                // 控制组件更新的"阀门"
                shouldComponentUpdate(){
                    console.log('Count---shouldComponentUpdate');
                    return true;
                }

                render(){
                    console.log('Count---render');
                    const {num} = this.state;
                    return(
                        <div>
                            <h1>当前和为:{num}</h1>
                            <button onClick={this.addBtn}>点我+1</button>
                            <button onClick={this.deleteBtn}>卸载组件</button>
                            <button onClick={this.force}>不更改任何状态中的数据,强制更新</button>
                        </div>
                    )
                }

                // 在更新之前获取快照
                getSnapshotBeforeUpdate(){
                    /* 
                        getSnapshotBeforeUpdate() 在最近一次渲染输出（提交到 DOM 节点）之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息（例如，滚动位置）。
                        此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()。
                    */
                    // 需要返回snapshot value (or null) 
                    console.log('getSnapshotBeforeUpdate');
                    return '哈哈哈哈snapshotValue哈哈哈哈哈'
                }

                // 组件挂载完毕的钩子
                componentDidMount(){
                    console.log('Count---componentDidMount')
                }

                // 加1按钮的回调函数
                addBtn = () =>{
                    // 获取原状态
                    const {num} = this.state;
                    // 更新状态
                    this.setState({num:num+1});
                }
                
                // 删除组件回调函数
                deleteBtn = () =>{
                    ReactDOM.unmountComponentAtNode(document.getElementById('test'));
                }
                // 强制更新的回调
                force = () =>{
                    // 强制更新
                    this.forceUpdate();
                }
                
                
                // 组件更新完毕的钩子
                // componentDidUpdate(先前Props,先前State)
                componentDidUpdate(preProps,preState,snapshotValue){
                    console.log('Count---componentDidUpdate',preProps,preState,snapshotValue);
                }

                // 组件将要卸载的钩子
                componentWillUnmount(){
                    console.log('Count---componentWillUnmount')
                }
            }
            // 渲染组件
            ReactDOM.render(<Count num={999}/>,document.getElementById('test'))
        </script>
    </body>
</html>